/*
 * $Id: InetAddress.hpp 130 2011-10-06 08:46:08Z hyunghwan.chung $
 *
   Copyright 2005-2009 Chung, Hyung-Hwan.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an  BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
 */

#ifndef _XP_NET_INETADDRESS_CLASS_
#define _XP_NET_INETADDRESS_CLASS_

#include <xp/net/Address.hpp>
#include <xp/bas/String.hpp>

#ifndef _WIN32
	#include <netdb.h>
	#include <arpa/inet.h>
	#include <netinet/in.h>
#endif

#if defined(__linux) && !defined(XP_HAVE_SS_FAMILY)
	#define ss_family __ss_family
#endif

XP_BEGIN_NAMESPACE2 (xp, net)

class InetAddress: public Address
{
public:
	InetAddress ();
	InetAddress (int family);
	InetAddress (const struct sockaddr_storage& adr);
	InetAddress (const struct sockaddr_in& adr);
	InetAddress (const struct sockaddr_in6& adr);

	InetAddress (const InetAddress& adr);

	// family
	enum {
		V0 = AF_UNSPEC,
		V4 = AF_INET,
		V6 = AF_INET6
	};

	enum 
	{
		MAX_HOST_LEN    = NI_MAXHOST,
		MAX_SERVICE_LEN = NI_MAXSERV
	};
	
	virtual InetAddress& operator= (const InetAddress& adr);
	virtual InetAddress& operator= (const struct sockaddr_storage& adr);
	virtual InetAddress& operator= (const struct sockaddr_in& adr);
	virtual InetAddress& operator= (const struct sockaddr_in6& adr);

	virtual bool operator== (const InetAddress& adr) const;
	virtual bool operator!= (const InetAddress& adr) const;

	bool hasEqualFamily (const InetAddress& addr) const;
	bool hasEqualHost (const InetAddress& addr) const;
	bool hasEqualService (const InetAddress& addr) const;

	virtual int family () const
	{
		return this->address_storage.ss_family;
	}

	virtual int type () const
	{
		return 0;
	}

	virtual addr_t* storage () const
	{
		return (addr_t*)&this->address_storage;
	}

	virtual len_t storageSize () const;

	virtual bool isLoopBack  () const;
	virtual bool isAnyLocal  () const;
	/*virtual bool isLinkLocal () const;*/
	/*virtual bool isSiteLocal () const;*/
	/*virtual bool isMulticast () const;*/

	virtual xp_uint16_t port () const; // return in network-byte order 
	virtual void setPort (xp_uint16_t v); // v in network-byte order


	virtual int getNumericHost (xp_char_t* buf, xp_size_t size) const;
	virtual int getNumericService (
		xp_char_t* buf, xp_size_t size) const;

	virtual int getHostName (xp_char_t* buf, xp_size_t size) const;
	virtual int getServiceName (xp_char_t* buf, xp_size_t size) const;

	virtual xp_char_t* numericHostStr (xp_char_t* buf, xp_size_t len) const;
	virtual xp_char_t* numericServiceStr (xp_char_t* buf, xp_size_t len) const;
	virtual xp::bas::String numericHost    () const;
	virtual xp::bas::String numericService () const;
	virtual xp::bas::String hostName       () const;
	virtual xp::bas::String serviceName    () const;

	virtual xp_char_t* numericStr (xp_char_t* buf, xp_size_t len) const;
	virtual xp::bas::String numericString () const;

	// the resolve function resolves a string to an address.
	// the string can be a numeric address string as well as a host name or 
	// a service name that can be resolved externally.
	static int resolve (const xp_char_t* service, InetAddress* address);

	//
	// To resolve a host name, you can call InetAddress::resolve.
	//   InetAddress x;
	//   InetAddress::resolve (XP_NULL, XP_T("www.abiyo.net"), &x);
	//
	// To resolve a host name to a specific family, you can specify
	// the family when you declare an InetAddress object.
	//   InetAddress x (InetAddress::V6);
	//   InetAddress::resolve (XP_NULL, XP_T("www.abiyo.net"), &x);
	//
	static int resolve (const xp_char_t* service, const xp_char_t* host, InetAddress* address);

	//
	// the fromString function converts a numeric address string to an address
	// the address part and the port number part can be separated with a colon.
	//   InetAddress addr;
	//   if (InetAddress::fromString (XP_T("[::1]:80"), &addr) <= -1) ...
	//
	static int fromString (const xp_char_t* str, xp_size_t len, InetAddress* address);
	static int fromString (const xp_char_t* str, InetAddress* address);

protected:
	struct sockaddr_storage address_storage;

	int resolve_address (
		const xp_char_t* service, const xp_char_t* host, 
		int family, int type, int* errnum);
};

XP_END_NAMESPACE2 (xp, net)

#endif
